﻿using IceCS.DataStructure.Core.LinearList.Exceptions;
using System;

namespace IceCS.DataStructure.Core.LinearList
{
    /// <summary>
    /// 顺序表
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class SequenceList<T> : ILinarList<T>
    {
        /// <summary>
        /// 存储数据
        /// </summary>
        private T[] _data;

        /// <summary>
        /// 数据表最大长度
        /// </summary>
        public int MaxCount { get; }


        /// <summary>
        /// 默认构造函数，数据表长度最大默认为10
        /// </summary>
        public SequenceList() : this(10)
        {

        }

        /// <summary>
        /// 非默认构造函数
        /// </summary>
        /// <param name="maxCount">数据表的最大长度</param>
        public SequenceList(int maxCount)
        {
            MaxCount = maxCount;
            _data = new T[MaxCount];
            Count = 0;
        }

        /// <summary>
        /// 索引器
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public T this[int index]
        {
            get { return _data[index]; }
            set { _data[index] = value; }
        }

        /// <summary>
        /// 清空表数据
        /// </summary>
        public void Clear()
        {
            Count = 0;
            _data = new T[MaxCount];
        }

        /// <summary>
        /// 在末尾附加节点
        /// </summary>
        /// <param name="item">节点数据</param>
        public void Add(T item)
        {
            if (IsFull)
            {
                throw new DSFullException();
            }
            var index = Count;
            _data[index] = item;
            Count++;
        }

        /// <summary>
        /// 插入节点，插入前需要使用 <see cref="IsFull"/> 判断是否满了,同时需要判断插入位置是否在正确范围
        /// </summary>
        /// <param name="index">插入节点的位置，索引从0开始</param>
        /// <param name="item">节点数据</param>
        public void Insert(int index, T item)
        {
            if (IsFull)
            {
                throw new DSFullException();
            }
            if (!IsInRightIndexRange(index))
            {
                throw new IndexOutOfRangeException("指定索引超出范围");
            }

            //从最后一个节点开始到插入节点挨个后移
            for (int i = Count - 1; i >= index; i--)
            {
                _data[i + 1] = _data[i];
            }
            _data[index] = item;
            Count++;
        }

        /// <summary>
        /// 删除节点
        /// </summary>
        /// <param name="item">数据</param>
        public void Remove(T item)
        {
            for (int i = 0; i < _data.Length; i++)
            {
                if ((object)_data[i] == (object)item)
                {
                    RemoveAt(i);
                    break;
                }
            }
        }

        /// <summary>
        /// 查找节点，查找前需要使用<see cref="IsEmpty"/>判断是否空了,同时需要判断查找位置是否在正确范围
        /// </summary>
        /// <param name="index">节点位置，索引从0开始</param>
        /// <returns>数据</returns>
        public void RemoveAt(int index)
        {
            if (IsEmpty)
            {
                throw new DSEmptyException();
            }

            if (!IsInRightIndexRange(index))
            {
                throw new IndexOutOfRangeException("指定索引超出范围");
            }

            //把要删除的节点的后面数据通通往前移一位即可
            for (int i = index; i < Count; i++)
            {
                _data[i] = _data[i + 1];
            }
            Count--;
        }

        /// <summary>
        /// 查找节点
        /// </summary>
        /// <param name="index">节点位置，索引从0开始</param>
        /// <returns>表数据</returns>
        public T FindIndex(int index)
        {
            if (IsEmpty || !IsInRightIndexRange(index))
            {
                throw new IndexOutOfRangeException("指定索引超出范围");
            }
            return _data[index];
        }

        /// <summary>
        /// 查找节点
        /// </summary>
        /// <param name="match">判断节点相等的条件</param>
        /// <returns>表数据</returns>
        public T Find(Func<T, bool> match)
        {
            if (IsEmpty)
            {
                throw new DSEmptyException();
            }
            int i;
            for (i = 0; i < Count; i++)
            {
                if (match(_data[i]))
                {
                    break;
                }
            }
            if (i == Count)
            {
                return default;
            }
            return _data[i];
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public T[] GetAll() => _data;

        ///<inheritdoc/>
        public bool IsEmpty => Count == 0;

        ///<inheritdoc/>
        public bool IsFull => Count == MaxCount;
        /// <summary>
        /// 数据表当前长度
        /// </summary>
        public int Count { get; private set; }
        /// <summary>
        /// 是否在正确的索引范围内
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        private bool IsInRightIndexRange(int index) => index >= 0 && index < Count;
    }
}
